package com.dragon.mmochat.service;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.dragon.mmochat.MmochatMain;

//关键词过滤
public class MmochatFilterService {
	private static Logger log = LoggerFactory
			.getLogger(MmochatFilterService.class);

	private static final char endTag = (char) (1); // 关键词结束符
	@SuppressWarnings("unchecked")
	private static Map<Character, HashMap> filterMap = new HashMap<Character, HashMap>(
			1024);

	@SuppressWarnings("unchecked")
	public void init() {
		if (!MmochatMain.openMergeServer) {
			// 加载过滤词库
			log.debug("开始装载过滤字库...");
			File file = new File("base/forbidden.txt");
			List<String> filterWordList = new ArrayList<String>();
			if (file.exists()) {
				if (file.isFile()) {
					try {
						BufferedReader reader = new BufferedReader(
								new FileReader(file));
						String lineBuf;
						reader.readLine();
						while ((lineBuf = reader.readLine()) != null) {
							if (lineBuf.trim().length() > 0) {
								filterWordList.add(lineBuf.trim());
							}
						}
						reader.close();
					} catch (FileNotFoundException e) {
						e.printStackTrace();
						throw new RuntimeException("forbidden.txt缺失!");
					} catch (IOException e) {
						e.printStackTrace();
						throw new RuntimeException("forbidden.txt读取出错!");
					}
				}
			}
			log.debug("装载了" + filterWordList.size() + "个过滤字");

			for (String filterWord : filterWordList) {
				char[] charArray = filterWord.trim().toCharArray();
				int len = charArray.length;
				if (len > 0) {
					Map<Character, HashMap> subMap = filterMap;
					for (int i = 0; i < len - 1; i++) {
						Map<Character, HashMap> obj = subMap.get(charArray[i]);
						if (obj == null) {
							// 新索引，增加HashMap
							int size = (int) Math.max(2, 16 / Math.pow(2, i));
							HashMap<Character, HashMap> subMapTmp = new HashMap<Character, HashMap>(
									size);
							subMap.put(charArray[i], subMapTmp);
							subMap = subMapTmp;
						} else {
							// 索引已经存在
							subMap = obj;
						}
					}
					// 处理最后一个字符
					Map<Character, HashMap> obj = subMap
							.get(charArray[len - 1]);
					if (obj == null) {
						// 新索引，增加HashMap，并设置结束符
						int size = (int) Math.max(2, 16 / Math.pow(2, len - 1));
						HashMap<Character, HashMap> subMapTmp = new HashMap<Character, HashMap>(
								size);
						subMapTmp.put(endTag, null);
						subMap.put(charArray[len - 1], subMapTmp);
					} else {
						// 索引已经存在,设置结束符
						obj.put(endTag, null);
					}
				}
			}
		}
	}

	// 返回是否包含需要过滤的词,匹配到最短的关键词就返回结果
	// 1万次执行大约耗时30ms
	@SuppressWarnings("unchecked")
	public static boolean isHasFilterWord(String info) {
		if (info == null || info.length() == 0) {
			return false;
		}
		char[] charArray = info.toLowerCase().toCharArray();
		int len = charArray.length;
		for (int i = 0; i < len; i++) {
			int index = i;
			Map<Character, HashMap> sub = filterMap.get(charArray[index]);
			while (sub != null) {
				if (sub.containsKey(endTag)) {
					// 匹配结束
					return true;
				} else {
					index++;
					if (index >= len) {
						// 字符串结束
						return false;
					}
					sub = sub.get(charArray[index]);
				}
			}
		}
		return false;
	}

	// 将字符串中包含的关键字过滤并替换为*，然后退回替换后的字符串
	// 1万次执行大约耗时170ms
	public static String getFilterString(String info) {
		return getFilterString(info, "*");
	}

	// 将字符串中包含的关键词过滤并替换为指定字符串，然后退回替换后的字符串
	// 尽量匹配最长的关键词再替换
	@SuppressWarnings("unchecked")
	public static String getFilterString(String info, String replaceTag) {
		if (info == null || info.length() == 0 || replaceTag == null
				|| replaceTag.length() == 0) {
			return info;
		}
		char[] charArray = info.toLowerCase().toCharArray();
		char[] bakArray = info.toCharArray();
		int len = charArray.length;
		String newInfo = "";
		int i = 0;
		while (i < len) {
			int end = -1;
			int index;
			Map<Character, HashMap> sub = filterMap;
			for (index = i; index < len; index++) {
				sub = sub.get(charArray[index]);
				if (sub == null) {
					// 匹配失败，将已匹配的最长字符进行替换
					if (end == -1) {
						// 没匹配到任何关键词
						newInfo += bakArray[i];
						i++;
						break;
					} else {
						// 将最长匹配字符串替换为特定字符
						for (int j = i; j <= end; j++) {
							newInfo += replaceTag;
						}
						i = end + 1;
						break;
					}
				} else {
					if (sub.containsKey(endTag)) {
						// 匹配
						end = index;
					}
				}
			}
			if (index >= len) {
				// 字符串结束
				if (end == -1) {
					// 没匹配到任何关键词
					newInfo += bakArray[i];
					i++;
				} else {
					// 将最长匹配字符串替换为特定字符
					for (int j = i; j <= end; j++) {
						newInfo += replaceTag;
					}
					i = end + 1;
				}
			}
		}
		return newInfo;
	}
}
